package org.example.myleet.rosalind.prsm;

import org.example.myleet.rosalind.utils.AminoAcidMassReader;

import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 本题难在理解题意，先看题目要求
 * 1、针对每个已知的peptide，先求出每个已知peptide的Complete Spectrum，也就是peptide的所有前缀和所有后缀的质量
 * 2、peptide下面的是Multiset，题目称为R，是一个未知peptide在质谱中产生的一些读数
 * 3、然后求R与每个已知peptide的Complete Spectrum multiset的Minkowski difference（也就是之前题目提到的Spectral Convolution）
 * 4、针对每一组Minkowski difference，查询里面的最大multiplicity，作为已知peptide与R产生的Minkowski difference的最大multiplicity
 * 5、输出最大的multiplicity以及对应的抑制peptide
 * 关于Spectral Convolution：https://rosalind.info/glossary/spectral-convolution/
 * 关于Minkowski difference：https://rosalind.info/glossary/minkowski-difference/
 * 关于Multiplicity：https://rosalind.info/glossary/multiplicity/
 * 关于Multiset：https://rosalind.info/glossary/multiset/
 */
public class Solution {
    public static void main(String[] args) throws IOException {
        Solution solution = new Solution();
        String path = solution.getClass().getResource("").getPath() + "example.txt";
        try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path)))) {
            //读取数据
            String line = br.readLine();
            int n = Integer.parseInt(line.trim());
            List<String> peptides = new ArrayList<>(n);
            for (int i = 0; i < n; ++i) {
                peptides.add(br.readLine().trim());
            }
            List<BigDecimal> R = new ArrayList<>();
            while (null != (line = br.readLine())) {
                line = line.trim();
                if (line.length() < 1) {
                    break;
                }
                R.add(new BigDecimal(line));
            }
            Map<String, BigDecimal> aminoAcidMapMass = AminoAcidMassReader.getAminoAcidMassMap();
            //结果保存的map
            Map<String, Integer> peptideMapMultiplicity = new HashMap<>(peptides.size());
            for (String peptide : peptides) {
                //求已知peptide的complete spectrum
                List<BigDecimal> sk = new ArrayList<>(2 * peptide.length());
                for (int i = 1; i < peptide.length(); ++i) {
                    sk.add(getPeptideMass(peptide.substring(0, i), aminoAcidMapMass));
                }
                for (int i = 0; i < peptide.length(); ++i) {
                    sk.add(getPeptideMass(peptide.substring(i), aminoAcidMapMass));
                }
                //求Minkowski difference
                List<BigDecimal> minkowskiDifference = new ArrayList<>(R.size() * sk.size());
                for (BigDecimal r : R) {
                    for (BigDecimal s : sk) {
                        minkowskiDifference.add(r.subtract(s));
                    }
                }
                //求Max multiplicity
                int maxMultiplicity = 0;
                Map<BigDecimal, Integer> multiplicityMap = new HashMap<>(minkowskiDifference.size());
                for (BigDecimal difference : minkowskiDifference) {
                    int multiplicity = multiplicityMap.getOrDefault(difference, 0) + 1;
                    multiplicityMap.put(difference, multiplicity);
                    maxMultiplicity = Math.max(maxMultiplicity, multiplicity);
                }
                peptideMapMultiplicity.put(peptide, maxMultiplicity);
            }
//            System.out.println(peptideMapMultiplicity);
            int maxMultiplicity = 0;
            String candidateAnswer = "";
            for (Map.Entry<String, Integer> entry : peptideMapMultiplicity.entrySet()) {
                if (entry.getValue() >= maxMultiplicity) {
                    maxMultiplicity = entry.getValue();
                    candidateAnswer = entry.getKey();
                }
            }
            System.out.println(maxMultiplicity);
            System.out.println(candidateAnswer);
        }
    }

    private static BigDecimal getPeptideMass(String peptide, Map<String, BigDecimal> aminoAcidMapMass) {
        BigDecimal totalMass = BigDecimal.ZERO;
        for (int i = 0; i < peptide.length(); ++i) {
            totalMass = totalMass.add(aminoAcidMapMass.get(peptide.substring(i, i + 1)));
        }
//        System.out.printf("%s\t\t%s\n", peptide, totalMass.toPlainString());
        return totalMass;
    }
}
